package com.atguigu.gmall.activity.mq;

import com.atguigu.gmall.activity.component.SeckillLocalCache;
import com.atguigu.gmall.activity.mq.to.SeckillSuccessTo;
import com.atguigu.gmall.activity.service.SeckillService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.list.Goods;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.mq.MqConst;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class SeckillMqListener {

    @Autowired
    SeckillService seckillService;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    SeckillLocalCache seckillLocalCache;

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = MqConst.SECKILL_UPGOODS_QUEUE, durable = "true", autoDelete = "false", exclusive = "false"),
                    exchange = @Exchange(value = MqConst.SECKILL_EXCHANGE, durable = "true", autoDelete = "false", type = "topic"),
                    key = {MqConst.SECKILL_UPGOODS_RK}
            )
    })
    public void listenUpGoodsNews(Message message, Channel channel, String date) throws IOException {
        try {
            //清空昨天的
            seckillService.clearBeforeDatas();

            //1、查询当前系统需要上架的所有商品并保存到redis
            List<SeckillGoods> seckillGoods = seckillService.getCurrentSeckillGoods();
            //2、发送通知给其他人，同步本地缓存（发布订阅模式）
            redisTemplate.convertAndSend(SeckillLocalCache.channel_key, SeckillLocalCache.goods_up);

            //3、准备分布式信号量
            //给消息队列发送消息，以免分布式信号量，在执行定时任务的期间炸了
            for (SeckillGoods good : seckillGoods) {
                RSemaphore semaphore = redissonClient.getSemaphore(RedisConst.SECKILL_STOCK_PREFIX + good.getSkuId());
                //信号量初始化 上架数量 - 已经秒了数量
                int count = good.getNum() - good.getStockCount();
                //判断如果信号量已经做了就不用再做了
                //返回信号量中有多少信号

                //初始化信号
                semaphore.trySetPermits(count);
                semaphore.expire(1, TimeUnit.DAYS);

            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }


    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = MqConst.SECKILL_SUCCESS_QUEUE, durable = "true", autoDelete = "false", exclusive = "false"),
                    exchange = @Exchange(value = MqConst.SECKILL_EXCHANGE, durable = "true", autoDelete = "false", type = "topic"),
                    key = {MqConst.SECKILL_SUCCESS_RK}
            )
    })
    public void listenSeckillSuccess(Message message, Channel channel, SeckillSuccessTo success) throws IOException {
        //收到秒杀成功的数据，预准备订单信息
        //生成一个订单存到redis中
        try {
            OrderInfo orderInfo = prepareOrder(success);
            String strJson = new ObjectMapper().writeValueAsString(orderInfo);
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            //给redis中保存
            operations.set(RedisConst.SECKILL_USER + orderInfo.getUserId(),strJson);

            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (JsonProcessingException e) {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
        }


    }

    private OrderInfo prepareOrder(SeckillSuccessTo success){
        Long skuId = success.getSkuId();
        String userId = success.getUserId();
        SeckillGoods goods = seckillLocalCache.getSeckillGoodsBySkuId(skuId);
        OrderInfo orderInfo = new OrderInfo();
        List<OrderDetail> details = new ArrayList<>();
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setSkuId(goods.getSkuId());
        orderDetail.setSkuName(goods.getSkuName());
        orderDetail.setImgUrl(goods.getSkuDefaultImg());
        orderDetail.setOrderPrice(goods.getPrice());
        orderDetail.setSkuNum(goods.getNum());

        details.add(orderDetail);

        orderInfo.setOrderDetailList(details);//当前这个订单，买了什么
        orderInfo.setUserId(Long.parseLong(userId));
        //订单计算一下总额
        orderInfo.sumTotalAmount();

        return orderInfo;
    }
}
